/*
 * File: MualGUI.cpp
 * =================
 * Source file of Mual Graphics User Interface(MGUI) and Mual Desktop 
 * Environment(MDE).
 * License: GPL
 * Author: Charles Weng
 */
#include <iostream>
#include <cstdlib>
#include <string>
#include <windows.h>
#include <conio.h>
#include <limits>
#include "MualGUI.h"
using namespace std;

static XDesktop MDE;
void gotoxy(int x, int y)
{
	COORD coord;
	coord.X = x; coord.Y = y;
	SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
}
int DrawTitle(Window hwnd)
{
    int i,k;
    bool newspace;
//    for(i=0;i<hwnd->Left;i++) cout<<" ";
//    cout<<"||";
//    for(i=0;i<hwnd->Right-4;i++) cout<<"=";
//    cout<<"||"<<endl;
	gotoxy(hwnd->Left,hwnd->Top);
    cout<<"||";
    k=(hwnd->Right-4 - hwnd->Title.length())/2;
    newspace=false;
    if(k*2+4+(int)hwnd->Title.length()<hwnd->Right) newspace=true;
    for(i=0;i<k;i++) cout<<"-";
    cout<<(hwnd->Title);
    if(newspace) cout<<"-";
    for(i=0;i<k;i++) cout<<"-";
    cout<<"||"<<endl;
	gotoxy(hwnd->Left,hwnd->Top+1);
    cout<<"||";
    for(i=0;i<hwnd->Right-4;i++) cout<<"-";
    cout<<"||"<<endl;
	gotoxy(0,24);
    return 0;
}
int DrawWindow(Window hwnd)
{
    int i,j;
    if(hwnd==NULL) return -1;
    DrawTitle(hwnd);
    for(j=hwnd->Top+2;j<hwnd->Bottom-1;j++){
		gotoxy(hwnd->Left,j);
//        for(i=0;i<hwnd->Left;i++) cout<<" ";
        cout<<"||";
        for(i=0;i<hwnd->Right-4;i++) cout<<" ";
        cout<<"||"<<endl;
    }
	gotoxy(hwnd->Left,j);
    cout<<"||";
    for(i=0;i<hwnd->Right-4;i++) cout<<"=";
    cout<<"||"<<endl;
	gotoxy(0,24);
    return 0;
}
int ClearBoard()
{
#ifdef WIN32
    system("cls");
#else
	system("clear");
#endif
    return 0;
}
Window NewWindow(int Top,int Bottom,int Left,int Right,string Title)
{
    Window hwnd;
    hwnd=new win;
	if(Bottom>=25 || Right>=80) return NULL;
    hwnd->Bottom=Bottom;
    hwnd->Left=Left;
    hwnd->Top=Top;
    if(Right-Left-4<(int)Title.length()){
        free(hwnd);
        return NULL;
    }
    hwnd->Right=Right;
    hwnd->Title=Title;
	hwnd->vBottom=Bottom-2;
	hwnd->vLeft=3;
	hwnd->vRight=Right-3;
	hwnd->vTop=TitleHeight+1;
	hwnd->isVarLocked=false;
	hwnd->var = new Element;
	hwnd->var->str="";
	hwnd->var->x=0;
	hwnd->var->y=0;
	hwnd->var->next=NULL;
    return hwnd;
}
int RegisterWindow(Window Modules)
{
    XDesktop s,p;
    if(!isConfigured) return -1;
    if(Modules==NULL) return -1;
    p=MDE;
    s=NULL;
    while(p->next!=NULL){
        p=p->next;
    }
    s=new Display;
    s->Frame=Modules;
    p->next=s;
    s->FID=p->FID+1;
    s->next=NULL;
	s->isHide=false;
    return s->FID;
}
int StartX()
{
	MDE = new Display;
	MDE->FID=0;
	MDE->Frame = NULL;
	MDE->isHide = true;
	MDE->next = NULL;
	isConfigured = true;
	return 0;
}
int XDaemon()
{
	string cmd,tle,horn;
	int i,t,l,r,b,m;
	gotoxy(0,23);
	for(i=0;i<79;i++) cout<<" ";
	gotoxy(0,23);
	if(!isConfigured){
		ClearBoard();
		cout<<" ERR: X Server hasn't been configured, please run startx first."<<endl;
		return -1;
	}
	gotoxy(0,23);
	cout<<" X Actions $ ";
	myflush();
	getline(cin,cmd);
	if(cmd=="newwin"){
		gotoxy(0,23);
		for(i=0;i<79;i++) cout<<" ";
		gotoxy(0,23);
		cout<<" Input four number(top,left,right,bottom) $ ";
		cin>>t>>l>>r>>b;
		gotoxy(0,23);
		for(i=0;i<79;i++) cout<<" ";
		gotoxy(0,23);
		cout<<" Input title $ ";
		myflush();
		cin.clear();
		cin>>tle;
		Window hwnd;
		hwnd = NewWindow(t,b,l,r,tle);
		if(hwnd==NULL){
			gotoxy(0,23);
			for(i=0;i<79;i++) cout<<" ";
			gotoxy(0,23);
			cout<<" ERR: Unknown errors happened while creating window.";
			_getch();
			return 0;
		}else{
			RegisterWindow(hwnd);
		}
		Refresh();
	}else if(cmd=="quit"){
		EndX();
		return 1;
	}else if(cmd=="switch"){
		gotoxy(0,23);
		for(i=0;i<79;i++) cout<<" ";
		gotoxy(0,23);
		cout<<" Input the Window's Title $ ";
		myflush();
		cin>>tle;
		int m;
		m=SearchFID(tle);
		if(m==-1){
			gotoxy(0,23);
			for(i=0;i<79;i++) cout<<" ";
			gotoxy(0,23);
			cout<<" Window isn't exist!";
			_getch();
			return 0;
		}
		SwitchTo(m);
		Refresh();
	}else if(cmd=="refresh"){
		Refresh();
		return 0;
	}else if(cmd=="listwin"){
		list();
		return 0;
	}else if(cmd=="kill"){
		gotoxy(0,23);
		for(i=0;i<79;i++) cout<<" ";
		gotoxy(0,23);
		cout<<" Input the Window's Title $ ";
		myflush();
		cin>>tle;
		int m;
		m=SearchFID(tle);
		if(m==-1){
			gotoxy(0,23);
			for(i=0;i<79;i++) cout<<" ";
			gotoxy(0,23);
			cout<<" Window isn't exist!";
			_getch();
			return 0;
		}
		kill(m);
		Refresh();
	}else if(cmd=="killall"){
		killall();
		Refresh();
	}else if(cmd=="reload"){
		ReloadX();
		Refresh();
	}else if(cmd=="maxium"){
		gotoxy(0,23);
		for(i=0;i<79;i++) cout<<" ";
		gotoxy(0,23);
		cout<<" Window's title $ ";
		myflush();
		cin>>tle;
		if((m = SearchFID(tle))==-1){
			gotoxy(0,23);
			for(i=0;i<79;i++) cout<<" ";
			gotoxy(0,23);
			cout<<" Window does not exist!";
			_getch();
			return 0;
		}
		MaxiumWin(m);
		Refresh();
		return 0;
	}else if(cmd=="minium"){
		gotoxy(0,23);
		for(i=0;i<79;i++) cout<<" ";
		gotoxy(0,23);
		cout<<" Window's title $ ";
		myflush();
		cin>>tle;
		if((m = SearchFID(tle))==-1){
			gotoxy(0,23);
			for(i=0;i<79;i++) cout<<" ";
			gotoxy(0,23);
			cout<<" Window does not exist!";
			_getch();
			return 0;
		}
		MiniumWin(m);
		Refresh();
		return 0;
	}else if(cmd=="recover"){
		gotoxy(0,23);
		for(i=0;i<79;i++) cout<<" ";
		gotoxy(0,23);
		cout<<" Window's title $ ";
		myflush();
		cin>>tle;
		if((m = SearchFID(tle))==-1){
			gotoxy(0,23);
			for(i=0;i<79;i++) cout<<" ";
			gotoxy(0,23);
			cout<<" Window does not exist!";
			_getch();
			return 0;
		}
		RecoverWin(m);
		Refresh();
		return 0;
	}else if(cmd=="mover"){
		gotoxy(0,23);
		for(i=0;i<79;i++) cout<<" ";
		gotoxy(0,23);
		cout<<" Window's title $ ";
		cin>>tle;
		if((m = SearchFID(tle)) == -1){
			gotoxy(0,23);
			for(i=0;i<79;i++) cout<<" ";
			gotoxy(0,23);
			cout<<" Window does not exist!";
			_getch();
			return 0;
		}
		MoveRight(m);
		Refresh();
		return 0;
	}else if(cmd=="movel"){
		gotoxy(0,23);
		for(i=0;i<79;i++) cout<<" ";
		gotoxy(0,23);
		cout<<" Window's title $ ";
		cin>>tle;
		if((m = SearchFID(tle)) == -1){
			gotoxy(0,23);
			for(i=0;i<79;i++) cout<<" ";
			gotoxy(0,23);
			cout<<" Window does not exist!";
			_getch();
			return 0;
		}
		MoveLeft(m);
		Refresh();
		return 0;
	}else if(cmd=="moveu"){
		gotoxy(0,23);
		for(i=0;i<79;i++) cout<<" ";
		gotoxy(0,23);
		cout<<" Window's title $ ";
		cin>>tle;
		if((m = SearchFID(tle)) == -1){
			gotoxy(0,23);
			for(i=0;i<79;i++) cout<<" ";
			gotoxy(0,23);
			cout<<" Window does not exist!";
			_getch();
			return 0;
		}
		MoveUp(m);
		Refresh();
		return 0;
	}else if(cmd=="moved"){
		gotoxy(0,23);
		for(i=0;i<79;i++) cout<<" ";
		gotoxy(0,23);
		cout<<" Window's title $ ";
		cin>>tle;
		if((m = SearchFID(tle)) == -1){
			gotoxy(0,23);
			for(i=0;i<79;i++) cout<<" ";
			gotoxy(0,23);
			cout<<" Window does not exist!";
			_getch();
			return 0;
		}
		MoveDown(m);
		Refresh();
		return 0;
	}else if(cmd=="getframeinfo"){
		gotoxy(0,23);
		for(i=0;i<79;i++) cout<<" ";
		gotoxy(0,23);
		cout<<" Window's title $ ";
		cin>>tle;
		if((m = SearchFID(tle)) == -1){
			gotoxy(0,23);
			for(i=0;i<79;i++) cout<<" ";
			gotoxy(0,23);
			cout<<" Window does not exist!";
			_getch();
			return 0;
		}
		Window myhwnd;
		myhwnd = GetFrameInfo(m);
		ShowFrameInfo(myhwnd,m);
		return 0;
	}else if(cmd=="drawtext"){
		gotoxy(0,23);
		for(i=0;i<79;i++) cout<<" ";
		gotoxy(0,23);
		cout<<" Window's title $ ";
		cin>>tle;
		if((m = SearchFID(tle)) == -1){
			gotoxy(0,23);
			for(i=0;i<79;i++) cout<<" ";
			gotoxy(0,23);
			cout<<" Window does not exist!";
			_getch();
			return 0;
		}
		gotoxy(0,23);
		for(i=0;i<79;i++) cout<<" ";
		gotoxy(0,23);
		cout<<" Draw Position $ ";
		int x,y;
		cin>>x>>y;
		gotoxy(0,23);
		for(i=0;i<79;i++) cout<<" ";
		gotoxy(0,23);
		cout<<" Text $ ";
		string texta;
		cin>>texta;
		MyDrawText(m,x,y,texta);
		Refresh();
		return 0;
	}
	return 0;
}
int Refresh()
{
	XDesktop p;
	ClearBoard();
	p=MDE;
	while(p->next!=NULL){
		p=p->next;
		struct Element *s;
		if(!(p->isHide)){
		    DrawWindow(p->Frame);
			if(p!=NULL && p!=MDE){
				s=p->Frame->var;
				while(s->next!=NULL){
					s=s->next;
					MyDrawText(p->FID,s->x,s->y,s->str);
				}
			}
		}
	}
	return 0;
}
int SearchFID(string WindowTitle)
{
	XDesktop p;
	p=MDE;
	while(p->next!=NULL){
		p=p->next;
		if(p->Frame->Title==WindowTitle) return p->FID;
	}
	return -1;
}
int SwitchTo(int FID)
{
	XDesktop k,s,p;
	p=MDE;
	k=NULL;
	while(p->next!=NULL){
		k=p;
		p=p->next;
		if(p->FID==FID) break;
	}
	s=MDE;
	while(s->next!=NULL){
		s=s->next;
	}
	if(p->next==NULL) return 0;
	k->next=p->next;
	s->next=p;
	p->next=NULL;
	return 0;
}
int list()
{
	XDesktop p;
	int c=0;
	p=MDE;
	ClearBoard();
	while(p->next!=NULL){
		p=p->next;
		c++;
		cout<<p->FID<<"\t"<<p->Frame->Title<<(p->isHide?"\tInvisible":"\tVisible")<<endl;
		if(c%22==0){
			cout<<" Press any key to continue... ";
			_getch();
			ClearBoard();
		}
	}
	return 0;
}
int kill(int FID)
{
	XDesktop k,p;
	p=MDE;
	k=NULL;
	while(p->next!=NULL){
		k=p;
		p=p->next;
		if(p->FID==FID) break;
	}
	k->next=p->next;
	free(p);
	return 0;
}
int EndX()
{
	ClearBoard();
	free(MDE);
	isConfigured = false;
	return 0;
}
int ReloadX()
{
	EndX();
	StartX();
	return 0;
}
int killall()
{
	ReloadX();
	return 0;
}
Window GetFrameInfo(int FID)
{
	XDesktop p;
	p = MDE;
	while(p->next!=NULL){
		p=p->next;
		if(p->FID == FID) return p->Frame;
	}
	return NULL;
}
int MoveTo(int Top, int Left, int Right, int Bottom, int FID)
{
	if(Top<0 || Left<0 || Right>=80 || Bottom>=23){
		return -1;
	}
	Window hwnd;
	hwnd = GetFrameInfo(FID);
	hwnd->Top = Top;
	hwnd->vTop = Top+TitleHeight;
	hwnd->Left = Left;
	hwnd->vLeft = Left+2;
	hwnd->Right = Right;
	hwnd->vRight = Right-2;
	hwnd->Bottom = Bottom;
	hwnd->vBottom = Bottom-1;
	return 0;
}
int MoveRight(int FID)
{
	Window hwnd;
	if((hwnd = GetFrameInfo(FID)) == NULL) return -1;
	if(hwnd->Right+1<80){
		return MoveTo(hwnd->Top, hwnd->Left+1, hwnd->Right+1, hwnd->Bottom, FID);
	}
	return -1;
}
int MoveUp(int FID)
{
	Window hwnd;
	if((hwnd = GetFrameInfo(FID)) == NULL) return -1;
	if(hwnd->Top-1>=0){
		return MoveTo(hwnd->Top-1, hwnd->Left, hwnd->Right, hwnd->Bottom-1, FID);
	}
	return -1;
}
int MoveDown(int FID)
{
	Window hwnd;
	if((hwnd = GetFrameInfo(FID)) == NULL) return -1;
	if(hwnd->Bottom+1<23){
		return MoveTo(hwnd->Top+1, hwnd->Left, hwnd->Right, hwnd->Bottom+1, FID);
	}
	return -1;
}
int MoveLeft(int FID)
{
	Window hwnd;
	if((hwnd = GetFrameInfo(FID)) == NULL) return -1;
	if(hwnd->Left-1>=0){
		return MoveTo(hwnd->Top, hwnd->Left-1, hwnd->Right-1, hwnd->Bottom, FID);
	}
	return -1;
}
int MaxiumWin(int FID)
{
	MoveTo(0,0,79,22,FID);
	Refresh();
	return 0;
}
int MiniumWin(int FID)
{
	XDesktop p;
	p=MDE;
	while(p->next!=NULL){
		p=p->next;
		if(p->FID == FID){
			p->isHide = true;
			return 0;
		}
	}
	return -1;
}
int RecoverWin(int FID)
{
	XDesktop p;
	p=MDE;
	while(p->next!=NULL){
		p=p->next;
		if(p->FID == FID){
			p->isHide = false;
			return 0;
		}
	}
	return -1;
}
int myflush()
{
	return 0;
}

XDesktop FrameToDesktop(int FID)
{
	XDesktop p;
	p=MDE;
	while(p->next!=NULL){
		p=p->next;
		if(p->FID==FID){
			return p;
		}
	}
	return NULL;
}
int MyDrawText(int FID, int vTop, int vLeft, string _str)
{
	XDesktop p;
	Window w;
	p = FrameToDesktop(FID);
	if(p==NULL) return -1;
	if(p->Frame->isVarLocked) return 0;
	w=p->Frame;
	if(vTop<w->vTop || vLeft<w->vLeft || vLeft+_str.length()>w->vRight){
		return -1;
	}
	gotoxy(vTop+w->Top+1,vLeft+w->Left+1);
	cout<<_str;
	gotoxy(0,23);
	return 0;
}
int ShowFrameInfo(Window myhwnd, int FID)
{
	int i;
	int t=0,l=0,r=25,b=10,m;
	string tle("Info");
	Window hwnd;
	XDesktop n;
	hwnd = NewWindow(t,b,l,r,tle);
	if(hwnd==NULL){
		gotoxy(0,23);
		for(i=0;i<79;i++) cout<<" ";
		gotoxy(0,23);
		cout<<" ERR: Unknown errors happened while creating window.";
		_getch();
		return 0;
	}else{
		m=RegisterWindow(hwnd);
	}
	n=FrameToDesktop(m);
	n->Frame->isVarLocked=false;
	Refresh();
	tle="Top : ";
	tle+=convert(myhwnd->Top);
	struct Element *k,*d;
	k=n->Frame->var;
	while(k->next!=NULL) k=k->next;
	d=new Element;
	k->next=d;
	d->str=tle;
	d->x=3; d->y=3;
	d->next=NULL;
	tle="Left : ";
	tle+=convert(myhwnd->Left);
	k=n->Frame->var;
	while(k->next!=NULL) k=k->next;
	d=new Element;
	k->next=d;
	d->str=tle;
	d->x=3; d->y=4;
	d->next=NULL;
	tle="Right : ";
	tle+=convert(myhwnd->Right);
	k=n->Frame->var;
	while(k->next!=NULL) k=k->next;
	d=new Element;
	k->next=d;
	d->str=tle;
	d->x=3; d->y=5;
	d->next=NULL;
	tle="Bottom : ";
	tle+=convert(myhwnd->Bottom);
	k=n->Frame->var;
	while(k->next!=NULL) k=k->next;
	d=new Element;
	k->next=d;
	d->str=tle;
	d->x=3; d->y=6;
	d->next=NULL;
	Refresh();
	return 0;
}
string convert(int n) 
{ 
	static string c=""; 
	if(n<10) 
	{ 
		c=(char)(n%10+'0'); 
		return c; 
	} 
	else 
	{ 
		c=convert(n/10)+(char)(n%10+'0'); 
		return c; 
	} 
}